package com.gitee.wsl.net.ssdp.description.model.xml

import com.gitee.wsl.logger.Logger
import com.gitee.wsl.logger.info
import com.gitee.wsl.net.ssdp.description.xml.XmlElement
import kotlin.properties.Delegates

object ArgumentList {
    /**
     * Action parameter. UPnP vendors shall not add vendor-defined arguments to actions defined by a UPnP Forum working
     * committees.
     * @param name          - Name of formal parameter. The name should be chosen to reflect the semantic use of the
     *                          argument. shall not contain a hyphen character (“-”, 2D Hex in UTF-8). First character
     *                          shall be a USASCII letter (“A”-“Z”, “a”-“z”), USASCII digit (“0”-“9”), an underscore
     *                          (“_”), or a non-experimental Unicode letter or digit greater than U+007F. Succeeding
     *                          characters shall be a USASCII letter (“A”-“Z”, “a”-“z”), USASCII digit (“0”-“9”), an
     *                          underscore (“_”), a period (“.”), a Unicode combiningchar, an extender, or a
     *                          nonexperimental Unicode letter or digit greater than U+007F. The first three letters
     *                          shall not be “XML” in any combination of case. String. Case sensitive. Should
     *                          be < 32 characters.
     * @param direction     - Defines whether argument is an input or output parameter. shall be either “in” or “out”
     *                          and not both. All input arguments shall be listed before any output arguments.
     * @param retval        - Identifies at most one output argument as the return value. If included, shall be included
     *                          as a subelement of the first output argument. (Element only; no value.)
     * @param relatedStateVariable  - Shall be the name of a state variable. Case Sensitive. Defines the type of the
     *                                  argument; see further explanation below in this clause.
     */
    data class Argument(
        val name: String,
        val direction: String,
        val retval: String?,
        val relatedStateVariable: String
    ) {
        /**
         * Facilitates flexible deserialization and conditional validation
         */
        companion object {
            fun fromXml(xml: XmlElement): Argument {
                if (xml.tag != "argument") {
                    throw IllegalArgumentException("Unexpected element ${xml.tag} in ArgumentList")
                }
                var nameS by Delegates.notNull<String>()
                var directionS by Delegates.notNull<String>()
                var retvalS: String? = null
                var relatedStateVariableS by Delegates.notNull<String>()

                xml.children?.forEach {
                    when (it.tag) {
                        "name" -> nameS = it.get()
                        "direction" -> directionS = it.get()
                        "retval" -> retvalS = it.getOrNull<String>()
                        "relatedStateVariable" -> relatedStateVariableS = it.get()
                        else -> Logger.info("Unexpected tag ${it.tag}")
                    }
                }
                return Argument(nameS, directionS, retvalS, relatedStateVariableS)
            }
        }
    }


    fun fromXml(xml: XmlElement): List<Argument> = xml.children?.map(Argument::fromXml) ?: emptyList()

}